import os
import json
import time
import uuid
import base64
import requests
from datetime import datetime
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.hashes import Hash, SHA256
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from flask import current_app

class WechatPayAPI:
    """微信支付API工具类"""
    
    def __init__(self):
        self.appid = current_app.config['WECHAT_APPID']
        self.mchid = current_app.config['WECHAT_MCHID']
        self.serial_no = current_app.config['WECHAT_PAY_SERIAL_NO']
        self.api_key = current_app.config['WECHAT_PAY_APIKEY']
        self.private_key_path = current_app.config['WECHAT_PAY_PRIVATE_KEY_PATH']
        self.cert_path = current_app.config['WECHAT_PAY_CERT_PATH']
        self.notify_url = current_app.config['WECHAT_PAY_NOTIFY_URL']
        
        # 加载私钥
        self._load_private_key()
    
    def _load_private_key(self):
        """加载商户私钥"""
        try:
            with open(self.private_key_path, 'rb') as f:
                self.private_key = load_pem_private_key(f.read(), password=None)
        except Exception as e:
            current_app.logger.error(f"加载商户私钥失败: {str(e)}")
            self.private_key = None
    
    def _generate_sign(self, method, url_path, body=None):
        """生成请求签名"""
        timestamp = str(int(time.time()))
        nonce_str = str(uuid.uuid4()).replace('-', '')
        
        # 构造签名字符串
        canonical_url = url_path.split('?')[0]
        body_str = '' if body is None else json.dumps(body)
        
        sign_str = f"{method}\n{canonical_url}\n{timestamp}\n{nonce_str}\n{body_str}\n"
        
        # 使用私钥签名
        signature_algorithm = ec.ECDSA(SHA256())
        signature = self.private_key.sign(sign_str.encode('utf-8'), signature_algorithm)
        
        # Base64编码
        sign = base64.b64encode(signature).decode('utf-8')
        
        # 构造认证头
        auth = f'WECHATPAY2-SHA256-RSA2048 mchid="{self.mchid}",nonce_str="{nonce_str}",signature="{sign}",timestamp="{timestamp}",serial_no="{self.serial_no}"'
        
        return auth
    
    def _request(self, method, url_path, data=None):
        """发送请求到微信支付API"""
        url = f"https://api.mch.weixin.qq.com{url_path}"
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': self._generate_sign(method, url_path, data)
        }
        
        try:
            if method == 'GET':
                response = requests.get(url, headers=headers)
            elif method == 'POST':
                response = requests.post(url, headers=headers, json=data)
            else:
                raise ValueError(f"不支持的HTTP方法: {method}")
            
            # 检查响应状态
            response.raise_for_status()
            
            return response.json()
        except Exception as e:
            current_app.logger.error(f"请求微信支付API异常: {str(e)}")
            return None
    
    def create_jsapi_payment(self, params):
        """创建JSAPI支付订单"""
        url_path = '/v3/pay/transactions/jsapi'
        
        # 构建请求参数
        data = {
            'appid': self.appid,
            'mchid': self.mchid,
            'description': params.get('description', '体育场馆预约'),
            'out_trade_no': params.get('out_trade_no'),
            'notify_url': self.notify_url,
            'amount': params.get('amount'),
            'payer': params.get('payer')
        }
        
        # 发送请求
        result = self._request('POST', url_path, data)
        
        if result and 'prepay_id' in result:
            # 生成小程序调起支付的参数
            prepay_id = result['prepay_id']
            timestamp = str(int(time.time()))
            nonce_str = str(uuid.uuid4()).replace('-', '')
            package = f"prepay_id={prepay_id}"
            
            # 构造签名字符串
            sign_str = f"{self.appid}\n{timestamp}\n{nonce_str}\n{package}\n"
            
            # 使用私钥签名
            signature_algorithm = ec.ECDSA(SHA256())
            signature = self.private_key.sign(sign_str.encode('utf-8'), signature_algorithm)
            
            # 返回支付参数
            return {
                'appId': self.appid,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': 'RSA',
                'paySign': base64.b64encode(signature).decode('utf-8'),
                'prepay_id': prepay_id
            }
        
        return None
    
    def query_order(self, out_trade_no):
        """查询订单状态"""
        url_path = f'/v3/pay/transactions/out-trade-no/{out_trade_no}?mchid={self.mchid}'
        return self._request('GET', url_path)
    
    def create_native_payment(self, params):
        """创建Native支付订单（用于生成二维码）"""
        url_path = '/v3/pay/transactions/native'
        
        # 构建请求参数
        data = {
            'appid': self.appid,
            'mchid': self.mchid,
            'description': params.get('description', '体育场馆预约'),
            'out_trade_no': params.get('out_trade_no'),
            'notify_url': params.get('notify_url', self.notify_url),
            'amount': params.get('amount')
        }
        
        # 发送请求
        result = self._request('POST', url_path, data)
        
        if result and 'code_url' in result:
            return {
                'code_url': result['code_url'],
                'prepay_id': result.get('prepay_id', '')
            }
        
        return None
    
    def close_order(self, out_trade_no):
        """关闭订单"""
        url_path = f'/v3/pay/transactions/out-trade-no/{out_trade_no}/close'
        data = {'mchid': self.mchid}
        return self._request('POST', url_path, data)
    
    def parse_payment_notification(self, request):
        """解析支付回调通知"""
        try:
            # 获取请求数据
            data = request.json
            
            # 验证签名
            # TODO: 实现验签逻辑
            
            # 解密数据
            resource = data.get('resource', {})
            nonce = resource.get('nonce')
            ciphertext = resource.get('ciphertext')
            associated_data = resource.get('associated_data', '')
            
            # 解密
            api_key_bytes = self.api_key.encode('utf-8')
            nonce_bytes = base64.b64decode(nonce)
            ciphertext_bytes = base64.b64decode(ciphertext)
            associated_data_bytes = associated_data.encode('utf-8') if associated_data else b''
            
            # 使用AEAD_AES_256_GCM算法解密
            aesgcm = AESGCM(api_key_bytes)
            plaintext_bytes = aesgcm.decrypt(nonce_bytes, ciphertext_bytes, associated_data_bytes)
            
            # 解析为JSON
            plaintext = plaintext_bytes.decode('utf-8')
            data['resource']['ciphertext'] = plaintext
            
            return data
        except Exception as e:
            current_app.logger.error(f"解析支付回调异常: {str(e)}")
            return None 